﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;

namespace PcArduinoControl
{
	class Watchdog :
        IDisposable
	{
		public event WatchdogTimeoutHandler WatchdogTimeout;

		object mSendLock = new object();

        // For the record, these timer's events are raised on a thread pool thread
		Timer mSendTimer = new Timer();
		Timer mTimeoutTimer = new Timer();
		
		Arduino mArduino;
		Log mLog;

		double mTimeout;

		public Watchdog(double mssendinterval, double mstimeoutinterval, Arduino arduino)
		{
			mTimeout = mstimeoutinterval;
			mArduino = arduino;
			mLog = mArduino.Log;

			mSendTimer.Interval = mssendinterval;
			mSendTimer.Elapsed += new ElapsedEventHandler(mSendTimer_Elapsed);
			mSendTimer.AutoReset = true;
			mTimeoutTimer.Interval = mTimeout;
			mTimeoutTimer.Elapsed += new ElapsedEventHandler(mTimeoutTimer_Elapsed);
		}

		public void StartFeeding()
		{
			lock (mSendLock)
			{
				mSendTimer.Enabled = true;
			}
			
			mLog.WriteLine("Watchdog: Started Feeding");
		}

		public void StartWatching()
		{
            Feed();
			mTimeoutTimer.Enabled = true;
			mLog.WriteLine("Watchdog: Started Watching");

			// Send a Watchdog Feed to Arduino to avoid an early timeout.
			mArduino.WatchdogFeed();
		}

		public void Stop()
		{
			mTimeoutTimer.Enabled = false;

			lock (mSendLock)
			{
				mSendTimer.Enabled = false;
			}

			mLog.WriteLine("Watchdog: Stopped");
		}

        public void Dispose()
        {
            mTimeoutTimer.Dispose();
            mTimeoutTimer = null;
            mSendTimer.Dispose();
            mSendTimer = null;
			
            GC.SuppressFinalize(this);
        }

		public void Feed()
		{
			// Cause timer to reset.
			mTimeoutTimer.Interval = mTimeout;
		}

		void mSendTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			mArduino.WatchdogFeed();
		}

		void mTimeoutTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			mLog.WriteLine("Event: Watchdog timed out.");
			OnWatchdogTimeout();
		}

		protected void OnWatchdogTimeout()
		{
			var watchdogto = WatchdogTimeout;
			if (watchdogto != null)
				watchdogto.Invoke();
		}
	}
}
